/* * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wso2.carbon.device.mgt.iot.services; import org.apache.log4j.Logger; import org.eclipse.paho.client.mqttv3.*; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.iot.services.firealarm.FireAlarmControllerService; import java.io.File; import java.util.LinkedList; public class MQTTSubscriber implements MqttCallback { private static Logger log = Logger.getLogger(MQTTSubscriber.class); private MqttClient client; private String clientId = "out:"; private MqttConnectOptions options; private String subscribeTopic = "wso2" + File.separator + "iot" + File.separator + "+" + File.separator; private String clientWillTopic; // topic needs to be set from outside private MQTTSubscriber(String owner, String deviceType) { this.clientId += owner + ":" + deviceType; this.subscribeTopic += deviceType + File.separator + "#"; this.clientWillTopic = deviceType.toLowerCase() + File.separator + "disconnection"; this.initSubscriber(); } private void initSubscriber() { try { client = new MqttClient(FireAlarmControllerService.CONTROL_QUEUE_ENDPOINT, clientId, null); log.info("MQTT subscriber was created with ClientID : " + clientId); } catch (MqttException ex) { String errorMsg = "MQTT Client Error\n" + "\tReason: " + ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() + "\n\tException: " + ex; log.error(errorMsg); } options = new MqttConnectOptions(); options.setCleanSession(false); options.setWill(clientWillTopic, "connection crashed".getBytes(), 2, true); client.setCallback(this); } /** * @return the whether subscriber is connected to queue */ public boolean isConnected() { return client.isConnected(); } public void subscribe() throws DeviceManagementException { try { client.connect(options); log.info("Subscriber connected to queue at: " + FireAlarmControllerService.CONTROL_QUEUE_ENDPOINT); } catch (MqttSecurityException ex) { String errorMsg = "MQTT Security Exception when connecting to queue\n" + "\tReason: " + ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() + "\n\tException: " + ex; //throw if (log.isDebugEnabled()) { log.debug(errorMsg); } throw new DeviceManagementException(errorMsg, ex); } catch (MqttException ex) { String errorMsg = "MQTT Exception when connecting to queue\n" + "\tReason: " + ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() + "\n\tException: " + ex; //throw if (log.isDebugEnabled()) { log.debug(errorMsg); } throw new DeviceManagementException(errorMsg, ex); } try { client.subscribe(subscribeTopic, 0); log.info("Subscribed with client id: " + clientId); log.info("Subscribed to topic: " + subscribeTopic); } catch (MqttException ex) { String errorMsg = "MQTT Exception when trying to subscribe to topic: " + subscribeTopic + "\n\tReason: " + ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() + "\n\tException: " + ex; if (log.isDebugEnabled()) { log.debug(errorMsg); } } } /* * (non-Javadoc) * * @see * org.eclipse.paho.client.mqttv3.MqttCallback#connectionLost(java.lang. * Throwable) */ @Override public void connectionLost(Throwable arg0) { log.warn("Lost Connection for client: " + this.clientId + " to " + FireAlarmControllerService.CONTROL_QUEUE_ENDPOINT); Thread subscriberDaemon = new Thread() { public void run() { while (true) { if (!FireAlarmControllerService.getMQTTSubscriber().isConnected()) { if (log.isDebugEnabled()) { log.debug("Subscriber reconnecting to queue........"); } try { FireAlarmControllerService.getMQTTSubscriber().subscribe(); } catch (DeviceManagementException e) { if (log.isDebugEnabled()) { log.debug("Could not reconnect and subscribe to ControlQueue."); } } } else { return; } try { Thread.sleep(100); } catch (InterruptedException e) { log.error("An Interrupted Exception in Subscriber thread."); } } } }; subscriberDaemon.setDaemon(true); subscriberDaemon.start(); } /* * (non-Javadoc) * * @see * org.eclipse.paho.client.mqttv3.MqttCallback#deliveryComplete(org.eclipse * .paho.client.mqttv3.IMqttDeliveryToken) */ @Override public void deliveryComplete(IMqttDeliveryToken arg0) { log.info("Message for client " + this.clientId + "delivered successfully."); } /* * (non-Javadoc) * * @see * org.eclipse.paho.client.mqttv3.MqttCallback#messageArrived(java.lang. * String, org.eclipse.paho.client.mqttv3.MqttMessage) */ @Override public void messageArrived(final String arg0, final MqttMessage arg1) { Thread subscriberThread = new Thread() { public void run() { int lastIndex = arg0.lastIndexOf("/"); String deviceId = arg0.substring(lastIndex + 1); lastIndex = arg1.toString().lastIndexOf(":"); String msgContext = arg1.toString().substring(lastIndex + 1); LinkedList<String> deviceControlList = null; LinkedList<String> replyMessageList = null; if (msgContext.equals("IN")) { log.info("Recieved a control message: "); log.info("Control message topic: " + arg0); log.info("Control message: " + arg1.toString()); synchronized (FireAlarmControllerService.internalControlsQueue) { deviceControlList = FireAlarmControllerService.internalControlsQueue.get(deviceId); if (deviceControlList == null) { FireAlarmControllerService.internalControlsQueue .put(deviceId, deviceControlList = new LinkedList<String>()); } } deviceControlList.add(arg1.toString()); } else if (msgContext.equals("OUT")) { log.info("Recieved reply from a device: "); log.info("Reply message topic: " + arg0); log.info("Reply message: " + arg1.toString().substring(0, lastIndex)); synchronized (FireAlarmControllerService.replyMsgQueue) { replyMessageList = FireAlarmControllerService.replyMsgQueue.get(deviceId); if (replyMessageList == null) { FireAlarmControllerService.replyMsgQueue .put(deviceId, replyMessageList = new LinkedList<String>()); } } replyMessageList.add(arg1.toString()); } } }; subscriberThread.start(); } }